package com.sheng.leetcode.year2022.month04.day15;

import lombok.ToString;
import org.junit.Test;

import java.util.*;

/**
 * @author liusheng
 * @date 2022/04/15
 *
 * 385. 迷你语法分析器
 *
 * 给定一个字符串 s 表示一个整数嵌套列表，实现一个解析它的语法分析器并返回解析的结果 NestedInteger 。
 *
 * 列表中的每个元素只可能是整数或整数嵌套列表
 *
 *  
 *
 * 示例 1：
 *
 * 输入：s = "324",
 * 输出：324
 * 解释：你应该返回一个 NestedInteger 对象，其中只包含整数值 324。
 * 示例 2：
 *
 * 输入：s = "[123,[456,[789]]]",
 * 输出：[123,[456,[789]]]
 * 解释：返回一个 NestedInteger 对象包含一个有两个元素的嵌套列表：
 * 1. 一个 integer 包含值 123
 * 2. 一个包含两个元素的嵌套列表：
 *     i.  一个 integer 包含值 456
 *     ii. 一个包含一个元素的嵌套列表
 *          a. 一个 integer 包含值 789
 *  
 *
 * 提示：
 *
 * 1 <= s.length <= 5 * 104
 * s 由数字、方括号 "[]"、负号 '-' 、逗号 ','组成
 * 用例保证 s 是可解析的 NestedInteger
 * 输入中的所有值的范围是 [-106, 106]
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/mini-parser
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */
public class LeetCode0385 {

    @Test
    public void test01(){
        //String s = "324";
        String s = "[123,[456,[789]]]";
        System.out.println(new Solution().deserialize(s));
    }

}
// This is the interface that allows for creating nested lists.
// You should not implement it, or speculate about its implementation
@ToString
class NestedInteger {
    Integer v;
    List<NestedInteger> l;
    boolean single;

    // Constructor initializes an empty nested list.
    public NestedInteger() {
        single = false;
        l = new ArrayList<>();
    }

    // Constructor initializes a single integer.
    public NestedInteger(int value) {
        single = true;
        v = value;
    }

    // @return true if this NestedInteger holds a single integer, rather than a nested list.
    public boolean isInteger() {
        return single;
    }

    // @return the single integer that this NestedInteger holds, if it holds a single integer
    // Return null if this NestedInteger holds a nested list
    public Integer getInteger() {
        return single ? v : null;
    }

    // Set this NestedInteger to hold a single integer.
    public void setInteger(int value) {
        if (single) {
            v = value;
        }
    }

    // Set this NestedInteger to hold a nested list and adds a nested integer to it.
    public void add(NestedInteger ni) {
        if (!single) {
            l.add(ni);
        }
    }

    // @return the nested list that this NestedInteger holds, if it holds a nested list
    // Return empty list if this NestedInteger holds a single integer
    public List<NestedInteger> getList() {
        return single ? null : l;
    }
}
//class Solution {
//    public NestedInteger deserialize(String s) {
//        return null;
//    }
//}
//
class Solution {
    /**
     * 这个是特殊标记，用来表示 '['
     */
    static final NestedInteger SIGN = new NestedInteger(0);

    /**
     *
     * @param s s = "[-2,[234, 678]]"
     * @return NestedInteger
     */
    public NestedInteger deserialize(String s) {
        Deque<NestedInteger> deque = new ArrayDeque<>();
        char[] cs = s.toCharArray();
        // 遍历
        int n = cs.length, i = 0;
        while (i < n) {
            // 如果是 ',' 则跳过就可以
            if (cs[i] == ',' && ++i >= 0) {
                continue;
            } else if (cs[i] == '-' || (cs[i] >= '0' && cs[i] <= '9')) {
                // 满足可以解析为整数的条件: 负号开始，或者 0-9的数字
                // 如果i所在位置为-号，则将下一位赋值给j，否则不动
                int j = cs[i] == '-' ? i + 1 : i;
                // 用来记录当前连续的数字是多少
                int num = 0;
                while (j < n && (cs[j] >= '0' && cs[j] <= '9')) {
                    num = num * 10 + (cs[j++] - '0');
                }

                // 将 NestedInteger对象入栈后继续处理后面字符, 这里入栈的对象，包含的都是单个的 Integer
                deque.addLast(new NestedInteger(cs[i] == '-' ? -num : num));
                i = j;
            } else if (cs[i] == '[') {
                // 这个空的是为了遇到 ’]' 的时候，反过来往里面添加，请注意，调用 NestedInteger.add() 的时候会生成列表哦
                deque.addLast(new NestedInteger());
                // 这个 SIGN 是为了说明，我这里是一个 ‘['
                deque.addLast(SIGN);
                i++;
            } else {
                // 遇到 ’]'的时候
                List<NestedInteger> list = new ArrayList<>();
                while (!deque.isEmpty()) {
                    NestedInteger poll = deque.pollLast();
                    // 说明目前加入到list当中的NestedInteger对象，应属于同一个嵌套
                    if (poll == SIGN) {
                        break;
                    }
                    list.add(poll);
                }

                // 接着，我们将list中的添加到原来，遇到 ‘[' 的时候，入栈的 空 NestedInteger 对象当中，调用add方法添加
                for (int j = list.size() - 1; j >= 0; j--) {
                    // 小细节需要逆序添加
                    deque.peekLast().add(list.get(j));
                }
                // 继续判断下一个字符
                i++;
            }
        }
        // 这是最后的嵌套字符
        return deque.peekLast();
    }
}
//
//    // 这里用一个例子说明情况，首先需要明确，栈中，列表中，添加的都是 NestedInteger 对象
//    // s = "[-2,[234, 678]]" 遍历到第一个 ']' 的时候，此时栈对应的状态为  {空，SIGN, -2, 空，SIGN, 234, 678}
//    // 现在遇到了第一个 ']' ，那么我们需要将连续出栈 的 678,234 加到list，直到遇到SIGN, 也就是 list = [678,234] 然后逆序加到 空 中，使用add
//    // 则此时是：{空，SIGN, -2, [234, 678]}，下一步遇到了第二个 ']'，则此时也是连续出栈，此时的 list = [[234, 678], -2]
//    // 加到最开始的 空 中，
//    // {[-2,[234,678]]} ; 然后 return deque.peekLast(); 就是 [-2,[234,678]]


//class Solution {
//    static NestedInteger ph = new NestedInteger(0);
//    public NestedInteger deserialize(String s) {
//        Deque<NestedInteger> d = new ArrayDeque<>();
//        char[] cs = s.toCharArray();
//        int n = cs.length, i = 0;
//        while (i < n) {
//            if (cs[i] == ',' && ++i >= 0) continue;
//            if (cs[i] == '-' || (cs[i] >= '0' && cs[i] <= '9')) {
//                int j = cs[i] == '-' ? i + 1 : i, num = 0;
//                while (j < n && (cs[j] >= '0' && cs[j] <= '9')) num = num * 10 + (cs[j++] - '0');
//                d.addLast(new NestedInteger(cs[i] == '-' ? -num : num));
//                i = j;
//            } else if (cs[i] == '[') {
//                d.addLast(new NestedInteger());
//                d.addLast(ph);
//                i++;
//            } else {
//                List<NestedInteger> list = new ArrayList<>();
//                while (!d.isEmpty()) {
//                    NestedInteger poll = d.pollLast();
//                    if (poll == ph) break;
//                    list.add(poll);
//                }
//                for (int j = list.size() - 1; j >= 0; j--) d.peekLast().add(list.get(j));
//                i++;
//            }
//        }
//        return d.peekLast();
//    }
//}
//
//作者：AC_OIer
//链接：https://leetcode-cn.com/problems/mini-parser/solution/by-ac_oier-zuy6/
//来源：力扣（LeetCode）
//著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
//栈
//每个 [ 的出现意味着存在一个嵌套类型的 NestedInteger 实例，
// 同时每个 NestedInteger 实例（无论是嵌套类型还是数值类型）都归属于其最近一个左边的嵌套类型的 NestedInteger 实例（即其左边最近一个 [），
// 因此我们可以使用栈来处理。
//
//对出现的几类字符进行简单分情况讨论：
//
//,：跳过即可；
//- 或 数字：将连续段代表数值的字符串取出，创建数值型的 NestedInteger 实例并压入栈中；
//[：创建一个嵌套类型的 NestedInteger 实例并压入栈中，同时为了方便，同步压入一个起「标识」作用的 NestedInteger 对象；
//]：从栈中取出元素，直到遇到起「标识」作用的 NestedInteger 对象（说明找到与当前 ] 成对的 [），
// 将 [ 和 ] 之间的所有元素添加到 [ 所代指的嵌套 NestedInteger 实例中，然后将 [ 所代指的嵌套 NestedInteger 实例重新放入栈中。
//按照上述逻辑处理完整个 s，最终栈顶元素即是答案。
//
//作者：AC_OIer
//链接：https://leetcode-cn.com/problems/mini-parser/solution/by-ac_oier-zuy6/
//来源：力扣（LeetCode）
//著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
